home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_400
/
429_01
/
chess12
/
cplayer.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1994-03-30
|
6KB
|
222 lines
#include <limits.h>
#include "brdsize.hpp"
#include "chess.hpp"
#include "cplayer.hpp"
#include "chessui.hpp"
// returns a measurement of how much of the board is "covered" by
// the pieces of a given player. lots of extra points are given
// for "covering" the location around the opponent's king
LOCAL int coverage
(
const BOARD &board,
PIECECOLOR color,
POSITION whereEnemyKing
)
{
unsigned char map[NUMROWS][NUMCOLS];
// bit flags for elements of map
const unsigned char KINGAREA = 1;
const unsigned char COVERED = 2;
POSITION where;
POSITIONLIST moves;
int m, result = 0;
// initialize map
for (where.row = 0; where.row < NUMROWS; where.row++)
for (where.col = 0; where.col < NUMCOLS; where.col++)
map[where.row][where.col] = 0;
// set covered flag on all covered locations
for (where.row = 0; where.row < NUMROWS; where.row++)
for (where.col = 0; where.col < NUMCOLS; where.col++)
{
if (board.whatPiece(where))
if ((board.whatPiece(where)->whatColor() == color) &&
(board.whatPiece(where)->whatType() != TYPEPAWN))
{
board.whatPiece(where)->legalMoves(where, board, moves);
for (m = 0; m < moves.nMoves; m++)
map[moves.end[m].row][moves.end[m].col] = COVERED;
}
}
// flag locations to which enemy king could move
board.whatPiece(whereEnemyKing)->
legalMoves(whereEnemyKing, board, moves);
for (m = 0; m < moves.nMoves; m++)
map[moves.end[m].row][moves.end[m].col] |= KINGAREA;
// accumulate coverage points
for (where.row = 0; where.row < NUMROWS; where.row++)
for (where.col = 0; where.col < NUMCOLS; where.col++)
{
if (map[where.row][where.col] & COVERED)
{
if (map[where.row][where.col] & KINGAREA)
result += 20;
else
result += 1;
}
}
return(result);
}
LOCAL POSITION whereKing
(
const BOARD &board,
PIECECOLOR color
)
{
POSITION where;
for (where.row = 0; ; where.row++)
for (where.col = 0; where.col < NUMCOLS; where.col++)
{
if (board.whatPiece(where))
if (board.whatPiece(where)->whatColor() == color)
if (board.whatPiece(where)->whatType() == TYPEKING)
return(where);
}
}
// positive difference between two integers
LOCAL inline int absDiff(int a, int b)
{
a -= b;
return(a < 0 ? -a : a);
}
// the change in difference from a goal value between a starting
// and an ending value
LOCAL int oneDimHowClose(int start, int end, int goal)
{
int a = absDiff(start, goal);
int diff = a - absDiff(end, goal);
if ((a < 2) && (diff > 0))
return(0);
return(diff);
}
// the change in "threat" metric caused by a given piece moving from
// a starting position to an ending position in terms of trying to
// threaten a goal position
LOCAL int threatChange
(
POSITION start,
POSITION end,
POSITION goal,
PIECE *p
)
{
if (p->whatType() == TYPEPAWN)
return(absDiff(start.col, end.col) * 2);
return(oneDimHowClose(start.row, end.row, goal.row) +
oneDimHowClose(start.col, end.col, goal.col));
}
// for a given list of moves, find the one that best improves the
// "development" of a player's pieces. development is a combination
// of covering alot of the board, getting pieces close to the enemy's
// king, and restricting the enemy king's movement.
LOCAL int bestDevelopMove
(
BOARD &board,
PIECECOLOR moveColor,
BESTMOVES &bestMoves
)
{
POSITION whereEnemyKing = whereKing(board, OtherColor(moveColor));
int testMetric, bestMetric = INT_MIN;
int bestIndex, testIndex;
MOVEUNDODATA undoData;
for (testIndex = 0; testIndex < bestMoves.nMoves; testIndex++)
{
// engage in castlephilia
if (bestMoves.move[testIndex].type != NORMALMOVE)
return(testIndex);
board.doMove
(
bestMoves.move[testIndex].start,
bestMoves.move[testIndex].end,
undoData
);
if (bestMoves.move[testIndex].promoteType != TYPENOPIECE)
board.promote(bestMoves.move[testIndex].end,
bestMoves.move[testIndex].promoteType);
testMetric = undoData.capturedPiece ?
undoData.capturedPiece->whatValue() * 16 : 0;
testMetric += coverage(board, moveColor, whereEnemyKing) +
threatChange
(
bestMoves.move[testIndex].start,
bestMoves.move[testIndex].end,
whereEnemyKing,
board.whatPiece(bestMoves.move[testIndex].end)
) * 4;
if (testMetric > bestMetric)
{
bestIndex = testIndex;
bestMetric = testMetric;
}
if (bestMoves.move[testIndex].promoteType != TYPENOPIECE)
board.restorePawn(bestMoves.move[testIndex].end);
board.undoMove
(
bestMoves.move[testIndex].end,
bestMoves.move[testIndex].start,
undoData
);
}
return(bestIndex);
}
GAMESTATUS COMPUTERPLAYER::play(BOARD &board) const
{
BOARDMETRIC metric;
BESTMOVES bestMoves;
int best;
ChessUI.thinkingMessage(whatColor());
board.findBestMoves(lookAhead, whatColor(), metric, &bestMoves);
if (metric.kingSituation[whatColor()] != KINGOK)
{
// see if checkmate/stalemate current or predicted
if (lookAhead > 2)
board.findBestMoves(2, whatColor(), metric, &bestMoves);
if (metric.kingSituation[whatColor()] == KINGLOST)
{
ChessUI.clearMessage();
ChessUI.mated(whatColor());
return(GAMEOVER);
}
else if (metric.kingSituation[whatColor()] == STALEMATE)
{
ChessUI.clearMessage();
ChessUI.staleMated(whatColor());
return(GAMEOVER);
}
}
best = bestDevelopMove(board, whatColor(), bestMoves);
if (!ChessUI.computerMove(board, whatColor(),
bestMoves.move[best]))
return(GAMEOVER);
return(GAMECONTINUE);
}